package de.gameduell.framework.game.billard.controller {
	import de.gameduell.framework.application.protocol.MultiplayerProtocol;
	import de.gameduell.framework.debug.Debug;
	import de.gameduell.framework.game.billard.event.AnimationEvent;
	import de.gameduell.framework.game.billard.model.Ball;
	import de.gameduell.framework.game.billard.model.BillardSettings;
	
	import flash.events.Event;
	import flash.events.EventDispatcher;
	import flash.events.TimerEvent;
	import flash.utils.Timer;	

	/**
	 * organize the time based animation of the balls
	 */
	public class AnimationController extends EventDispatcher{
		
		/** model wich holds the billard specific settings (physical in most cases)*/	
		private var settings:BillardSettings;
		/** timer to update the balls */
		private	var animationTimer:Timer;	
		/** saved start time */
		private var animStartTime:Number;	
		/** ball models */	
		private var balls:Array; 
		/** max length of steps found in a ball */
		private	var ballSteps:int;
		/** true when animation is running */
		private var animating:Boolean;
		/** controller that manages the different pbillardengine instances */
		private var physicController:PhysicController;
		/** true when calculation is running*/
		private var calculating:Boolean;
	
		/** 
		 * constructor
		 */
		public function AnimationController(aSettings:BillardSettings,aPhysicController:PhysicController) {
			Debug.trace("AnimationController::AnimationController");
			animating 		 = false;	
			calculating		 = false;
			settings  		 = aSettings;
			physicController = aPhysicController;
		
			balls	  		 = physicController.balls.slice();
//			physicController.addEventListener(MultiplayerProtocol.SETUP, start);
			start();
		}
		
		/** 
		 * starts the animation
		 */
		public function start(event:Event = null):void{
			if(!animating){
				
				Debug.trace("AnimationController.start");
				animating 	   = true;
				
				ballSteps 	   = findMaxAnimLength();//Ball(balls[0]).animationLength;
				animationTimer = new Timer(1000/settings.getValue(BillardSettings.KEY_MOVIE_FPS));
				animStartTime  = (new Date()).valueOf();
				animationTimer.addEventListener(TimerEvent.TIMER, animateBalls);
				animationTimer.start();		
				dispatchEvent(new AnimationEvent(AnimationEvent.ANIMATION_START));
			}
		}
		
		/**
		 * find the max length of steps in all balls
		 */
		private function findMaxAnimLength():int{
			var max:int = 0;
			for each(var ball:Ball in balls){
				max = Math.max(max,ball.animationLength);
			}
			return max;
		}
		
		/**
		 * true when the animation is running at the moment
		 * 
		 * @return true when animating
		 */
		public function get running():Boolean{
			return animating;
		}
		
		/**
		 * animate all balls to the current step
		 * 
		 * @param event TimerEvent.TIMER
		 */
		private function animateBalls(event:Event):void {
			if(!calculating){
				calculating = true;
				var currTimer:Number   = new Date().valueOf();
				var passedTimer:Number = currTimer - animStartTime;
				var passedSeks:Number  = passedTimer/1000;
				var tempFrame:int 	   = Math.round(passedSeks * settings.getValue(BillardSettings.KEY_ANIMATION_FPS));
				var anmimOver:Boolean  = tempFrame >= ballSteps-1;
				var frame:int 		   = anmimOver ? ballSteps-1 : tempFrame;
						
				for (var i in balls) {
					balls[i].animate(frame < 0 ? 1: frame);
				}
				dispatchEvent(new AnimationEvent(AnimationEvent.ANIMATION_STEP));
		
				if(anmimOver){
					animationOver();
				}
				calculating = false;
			}
		}
		
		/**
		 * called when the animation is over
		 * and delete all pathes
		 */
		private function animationOver():void {	
			animationTimer.stop();
			animating = false;	
			for (var i:int = 0;i < balls.length; i++) {
				balls[i].deletePath();
			}	
			Debug.trace("animationOver");
			dispatchEvent(new AnimationEvent(AnimationEvent.ANIMATION_OVER));
		}
	}
}
